package cn.iocoder.boot.redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * RedisCuckooFilter 是一个基于 Redis 的布谷鸟过滤器实现，用于高效地判断元素是否存在于集合中。
 * 它利用 Redis 的布谷鸟过滤器功能，结合 Lua 脚本，实现分布式环境下的高效缓存穿透预防。
 */
public class RedisCuckooFilter {
    private JedisPool jedisPool;
    /**
     * 构造函数，初始化 RedisCuckooFilter。
     */
    public RedisCuckooFilter(String host, int port) {
        jedisPool = new JedisPool(host, port);
    }
    /**
     * 创建一个新的布谷鸟过滤器。
     */
    public void createFilter(String key, int capacity) {
        try (Jedis jedis = jedisPool.getResource()) {
            // 检查键是否存在，如果不存在，则创建布谷鸟过滤器
            if (!jedis.exists(key)) {
                // 使用 Lua 脚本调用 Redis 的 CF.RESERVE 命令来创建过滤器
                String script = "redis.call('CF.RESERVE', KEYS[1], ARGV[1])";
                jedis.eval(script, 1, key, String.valueOf(capacity));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 向布谷鸟过滤器中添加元素。
     * @return 如果添加成功返回 true，否则返回 false
     */
    public boolean addItem(String key, String item) {
        try (Jedis jedis = jedisPool.getResource()) {
            // 使用 Lua 脚本调用 Redis 的 CF.ADD 命令来添加元素
            String script = "redis.call('CF.ADD', KEYS[1], ARGV[1])";
            Object result = jedis.eval(script, 1, key, item);
            // 检查返回结果，判断是否添加成功
            return result != null && ((Long) result) == 1;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 检查元素是否存在于布谷鸟过滤器中。
     * @return 如果元素存在返回 true，否则返回 false
     */
    public boolean existsItem(String key, String item) {
        try (Jedis jedis = jedisPool.getResource()) {
            // 使用 Lua 脚本调用 Redis 的 CF.EXISTS 命令来检查元素是否存在
            String script = "redis.call('CF.EXISTS', KEYS[1], ARGV[1])";
            Object result = jedis.eval(script, 1, key, item);
            // 检查返回结果，判断元素是否存在
            return result != null && ((Long) result) == 1;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}





